/*! \file HXConfig.h
    \brief XML config file parsing for Head X.

	Head X | Flinders University | Martin Luerssen & Trent Lewis | 2009+
*/

#pragma once

struct HXLight;
struct HXBlend;
struct HXResource;
struct HXResourceGroup;
class HXPlayerConfig;
class HXRenderData;

//-----------------------------------------------------------------------------

//! OpenGL light parameters.
struct HXLight
{
	HXLight()
	  : ambient(0),
		diffuse(0),
        azimuth(0),
        elevation(0),
		reset(true) {}

    HXLight(float _ambient, // brightness
		    float _diffuse,
            float _azimuth,
            float _elevation,
			bool _reset)
	  : ambient(_ambient),
		diffuse(_diffuse),
        azimuth(_azimuth),
        elevation(_elevation),
		reset(_reset) {}

	void Clear() { ambient = 0; diffuse = 0; azimuth = 0; elevation = 0; reset = true; }
	void Default() { ambient = 0.3f; diffuse = 0.7f; azimuth = 0.1f; elevation = 0.0f; reset = true; }

    float ambient, diffuse, azimuth, elevation;
	bool reset;
};

//-----------------------------------------------------------------------------

#include "HXPlayer.h"
#include "HXViseme.h"

// XML parsing:
#include <stdio.h>
#include <objbase.h>
#include <msxml6.h>

//-----------------------------------------------------------------------------

//! Information about blendshapes.
struct HXBlend
{
	HXBlend() {}
	HXBlend(wstring& _id, 
			wstring& _fileName, 
			bool _isMaterialBlend)
		: id(_id),
		  fileName(_fileName),
		  isMaterialBlend(_isMaterialBlend) {}

	wstring id;
	wstring fileName;
	bool isMaterialBlend;
};

//! Information about a data object to load or already loaded.
struct HXResource
{
	HXResource() { Clear(); }
	HXResource(wstring& _modelName) { Clear(); modelName = _modelName; }
	void	Clear();
	bool	IsLoaded() { return renderIndex != -1; }
	wstring modelName, textureName, detailName;
	list<HXBlend> blendList;
	float shininess, alpha_threshold;
	bool center; // object auto-centered in view?
	int recomp_normal; // recompute normals at every (n-th) frame?
	int renderIndex; // model render index
	HXRenderData* pRender; // model render data
	int item; // file index
	HXResourceGroup* pGroup;
};

//! Common transformations for a HXResourceGroup.
struct HXResourceTransform
{
	HXResourceTransform() : rotX(0), rotY(0), rotZ(0), transX(0), transY(0), transZ(0), scaleX(1), scaleY(1), scaleZ(1), mvmIsCurrent(false) {} 
	float rotX, rotY, rotZ, transX, transY, transZ, scaleX, scaleY, scaleZ;
	HXMatrix4F mvm;
	bool mvmIsCurrent;
};

//! A hierarchy of resources.
struct HXResourceGroup
{
	HXResourceGroup();
	HXResourceGroup(const wstring& _name, HXResourceGroup* _pParent);
	HXResourceGroup* GetChild(const wstring& _name);
	HXResourceGroup* GetDescendant(const wstring& _name);
	size_t Size();
	void Expand(list<HXResource*>& _res);
	void ExpandGroup(list<HXResourceGroup*>& _res);
	void RemoveRenderIndex(int _index);
	void Clear();

	wstring name;
	HXResourceGroup* pParent;
	list<HXResourceGroup> children;
	list<HXResource> resources;
	HXResourceTransform transform;
};

//-----------------------------------------------------------------------------

//! Supported languages.
enum HXLanguage {
  English,
  Chinese
};

//-----------------------------------------------------------------------------

//! XML configuration data for Head X.
class HXPlayerConfig
{
public:
	HXPlayerConfig();
	bool LoadFromXML(wstring& xmlstring, bool isFilename, bool paramsOnly = false, bool* pbExpressionsAreCleared = NULL);
	size_t AddModelsFromXML(wstring& xmlstring, bool isFilename, bool ignoreImports = false);
	void Clear();

	HXResourceGroup resourceGroup;
	bool bImmediateModeRender, bUseShaders;
	wstring FGfileName;
	bool bApplyFGDetail;
	float FGmorphDuration;
	wstring FGmorphFlags;

	int renderFPS;
	wstring shaderDir;
	bool disableShaders, enableDepthShaders;
	int multisample;
	int maxDepthPasses;
	wstring backgroundName;
	float bgRedness, bgGreenness, bgBlueness;
	HXLight light1;
	HXLight light2;

	bool bIdleBehaviour, bCurlyTags, bBreakOnStop, bEchoInputs;
	wstring exprFileName;
	wstring logFileName;
	bool bAllowShortcutKeys;
	bool bSynapseCommands, bSynapseDirect, bSynapseFaceMorphs, bSynapseCamera, bBlockSynapse;
	bool bDynBG;
	wstring dynBGSynapse;
	int dynBGX, dynBGY;
	bool bWindowMaximize, bWindowMenu, bWindowBorder, bWindowOnTop, bWindowTransparent;
	int windowXPos, windowYPos, windowWidth, windowHeight;
	wstring windowTitle;
	wstring interactionMode;
	float fov;
	map<wstring, vector<HXExpression>> expressionMap;
	vector<vector<HXIdleExpression>> idleExpressionSets;

	bool bSubtitleOutput;
	bool bSubtitleInput;
	wstring subtitleInputPrefix;
	wstring subtitleOutputPrefix;
	float subtitleRedness;
	float subtitleBlueness;
	float subtitleGreenness;
	int subtitleFontSize;
	wstring subtitleFont;
	float subtitleX;
	float subtitleY;
	float subtitleZ;
	int subtitleLength;
	int subtitleBlinkDelay;

	wstring quickAction0_label;
	wstring quickAction1_label;
	wstring quickAction2_label;
	wstring quickAction3_label;
	wstring quickAction4_label;
	wstring quickAction5_label;
	wstring quickAction6_label;
	wstring quickAction7_label;
	wstring quickAction8_label;
	wstring quickAction9_label;
	wstring quickAction0_speak;
	wstring quickAction1_speak;
	wstring quickAction2_speak;
	wstring quickAction3_speak;
	wstring quickAction4_speak;
	wstring quickAction5_speak;
	wstring quickAction6_speak;
	wstring quickAction7_speak;
	wstring quickAction8_speak;
	wstring quickAction9_speak;

	wstring voiceEngine;
	wstring voiceName;
	HXLanguage voiceLanguage;
	int voicekHz;
	float voiceRate;
	float voiceAVSync;
	float voiceModulator;
	int mixFrames;
	float mixFactor;
	unsigned int rampFunc;
	float voiceOverlap;
	map<wstring,vector<vector<HXVisemeBlendShape>>> visemeMap;

	#ifdef _MORPHDEBUG
		wstring morphDumpFile;
	#endif

protected:
	void BlendModelLoad(IXMLDOMNode *pXMLDom, HXResource& res);
	void AddBlendshapes(IXMLDOMNode *pXMLDom, const wstring& nodeName, int groupIndex, vector<HXVisemeBlendShape>& vbsArray);
	void AddMovements(IXMLDOMNode *pXMLDom, const wstring& nodeName, int groupIndex, vector<HXMovement>& movArray);
	size_t AddModelsFromNode(IXMLDOMNode* pXMLDom, HXResourceGroup& parentGroup);
	void AddTransforms(IXMLDOMNode* pXMLDom, HXResourceGroup& rg);
	IXMLDOMDocument* DomFromCOM();
	VARIANT VariantString(BSTR str);
	VARIANT VariantString(const wstring& str);
	void ReportParseError(IXMLDOMDocument *pDom, char *desc);
	long CountChildNodesWithName(IXMLDOMNode *pXMLDom, const wstring& nodeName, int index, const wstring& childName);
	long CountNodes(IXMLDOMNode *pXMLDom, const wstring& nodeName);
	bool HasNode(IXMLDOMNode *pXMLDom, const wstring& nodeName, int index = 0);
	IXMLDOMNode* GetNode(IXMLDOMNode *pXMLDom, const wstring& nodeName, int index);
	bool ReadAttribute(IXMLDOMNode *pXMLDom, const wstring& nodeName, const wstring& attrName, wstring& attrValue, int index = 0);
};

//=============================================================================

extern HXPlayerConfig g_config;